In the last section we reviewed how to translate (i.e. shift) an image up, down, left, and right (or any combination). Now we are going to move on to our next image processing topic — rotation.
Rotation is exactly what it sounds like: rotating an image by some angle . We’ll use
to represent by how many degrees we are rotating the image. And later, I’ll provide another convenience method, rotate , to make performing rotations on images easier.
Objectives:
By the end of this topic you should understand rotation and know how to rotate an image using OpenCV.
Rotation
Similar to translation, and perhaps unsurprisingly, rotation by an angle, can be defined by constructing a matrix M in the form:
Given an (x, y)-Cartesian plane, this matrix can be used to rotate a vector degrees (counter-clockwise) about the origin. In this case, the origin is normally the center of the image; however, in practice we can define any arbitrary (x, y) coordinate as our rotation center.
From the original image I, the rotated image R is then obtained by simple matrix multiplication:
However, OpenCV also provides the ability to (1) scale (i.e. resize) an image and (2) provide an arbitrary rotation center to perform the rotation about.
Our modified rotation matrix M is thus:
Where:
If the mathematics is starting to get a bit overwhelming, no worries — we’re about to jump into some code that will make these concepts a lot more clear.
Open up a new file, name it rotate.py , and let’s get started:
Lines 1-5 again import the packages we need. You should especially take note of the imutils package — once again we will be defining a convenience method to make our lives easier.
Lines 8-10 construct our argument parser. We only need one argument, --image , which is the path to the image we are going to use for our rotation example. We then load our image off disk and display it.
For a point of reference, here is our original image prior to any rotation being performed:
When we rotate an image, we need to specify which point we want to rotate about. In most cases, you will want to rotate around the center of an image; however, OpenCV allows you to specify any arbitrary point you want to rotate around (as detailed above). Let’s just go ahead and rotate about the center of the image. Lines 17 and 18 grab the width and height of the image, then proceed to divide each component by 2 to determine the center of the image.
Just as we defined a matrix to translate an image, we also define a matrix to rotate the image. Instead of manually constructing the matrix using NumPy (which can be a bit tedious), we’ll just make a call to the cv2.getRotationMatrix2D method on Line 21.
The cv2.getRotationMatrix2D function takes three arguments. The first argument is the point in which we want to rotate the image about (in this case, the center of the image). We then specify , the number of (counter-clockwise) degrees we are going to rotate the image by. In this case, we are going to rotate the image 45 degrees. The last argument is the scale of the image. We haven’t discussed resizing an image yet, but here you can specify a floating point value, where 1.0 means the same, original dimensions of the image are used. However, if you specified a value of 2.0, the image would be doubled in size. Similarly, a value of 0.5 halve the size of the image.
Once we have our rotation matrix M from the cv2.getRotationMatrix2D function, we can apply the rotation to our image using the cv2.warpAffine method on Line 22. The first argument to this function is the image we want to rotate. We then specify our rotation matrix M along with the output dimensions (width and height) of our image. Line 23 then shows our image rotated by 45 degrees.
When can see the output of our 45 degree rotation below:
As you can see, our image has been rotated. But also take a second to note that OpenCV does not automatically allocate space for our entire rotated image to fit into the frame. In fact, this is the intended behavior! If you want the entire image to fit into view after the rotation you’ll need to modify the width and height, denoted as (w, h) in the cv2.warpAffine function.
On Lines 26-28 we perform another rotation. The code is identical to that Lines 21-23, only this time we are rotating by -90 degrees rather than 45:
Figure 2: By specifying a negative angle value we can rotate our image 90 clockwise rather than counter-clockwise.
Up until this point we have only rotated an image about the center of the image. But what if we wanted to rotate the image about some arbitrary point?
Let’s go ahead and see how this can be accomplished:
By now this code should look fairly standard for performing a rotation. However, take a note of the first argument of the cv2.getRotationMatrix2D function — here we are indicating that we want to rotate the image about a point that is 50 pixels to the left and 50 pixels above the center of the image.
When we apply this rotation, our output image looks like this:
Clearly we can see that the center of the rotation is no longer the center of the image — it’s the (x, y)-coordinate that is both 50 pixels to the left and 50 pixels above the calculated center of the image.
However, just like translating an image, making calls to both cv2.getRotationMatrix2D and cv2.warpAffine can become quite tedious — not to mention it also makes our code substantially more verbose.
Let’s reduce the amount of code we have to write and define our own custom rotate method in the imutils package:
Our new rotate method takes four arguments. The first is our image. The second is the angle in which we want to rotate the image. We provide two optional keyword arguments, center and scale . The center parameter is the (x, y)-coordinate in which we wish to rotate our image about. If a value of None is provided, the method automatically determines the center of the image on Lines 19 and 20. Finally, the scale parameter is used to handle if the size of the image should be changed during the rotation. The scale parameter has a default value of 1.0, implying that no resizing should be done.
The actual rotation of the image takes place on Lines 23 and 24, were we construct our rotation matrix M and apply it to the image. Finally, our image is returned on Line 27.
Now that we have defined our rotate method, let’s apply it:
Here we are rotating our image by 180 degrees — but we were able to make our code substantially less verbose by using the rotate method of imutils .
The figure below displays the output of our rotation:
Figure 4: Using the rotate convenience function of the imutils package to rotate our image 180 degrees counter-clockwise.
And that’s all there is to it!
Summary
In this topic you learned how a rotation matrix is used to rotate an image about an arbitrary point in the Cartesian space. You then learned how OpenCV utilizes this matrix to perform rotations.
From there we viewed a few examples of rotating an image, followed by defining our own convenience function to make rotating images easier.
In the next topic we’ll explore resizing, and how different interpolation methods can give you dramatically different results when resizing your images.